#ifndef HUFFMAN_H
#define HUFFMAN_H

#include "../../include/hzstream.h"
#include "../include/storage.h"
#include <stdint.h>
#include <cstdlib>

using namespace storage;

namespace hfm{

class Node;
class HFM:public Storage{
public:
	HFM();
	virtual ~HFM();
	int encode(uint8_t* in_buf, uint8_t* out_buf, uint32_t buf_size);
	int decode(uint8_t* in_buf, uint8_t* out_buf, uint32_t buf_size);
	
	void encode(hzstream* hz);
	void decode(hzstream* hz);

	int* getAlphabet();
	void setAlphabet(int* alphabet);
	int getData_size();

private:
	void constructTree();
	void countWeights(const uint8_t* in_buf, int buf_size);

	void tree2arrays(Node *tree, int level, int num, bool right);

	int findCharacter(uint32_t c, int bits_num);

	uint32_t generateMask(int size);

	uint16_t getBitsFromBuffer(uint32_t buff, int bits);

	void init();

	Node* tree;

	static const int alphabet_size = 256;

	///Array containing used alphabet_weights
	uint32_t alphabet_weights[alphabet_size];
	int32_t num_of_bits[alphabet_size];

	int data_size;
	int used_alph_size;
};


class Node {
public:
	Node();
	Node(Node* node);
	Node(uint8_t c, int weight, bool use_value = false, Node *parent = NULL, Node* left = NULL, Node* right = NULL);
	~Node();

	bool compareWithNode(Node* node);
    uint8_t getC() const;
    Node *getLeft() const;
    Node *getParent() const;
    Node *getRight() const;
    int getWeight() const;
    bool getUseValue() const;
    void setC(uint8_t c);
    void setLeft(Node *left);
    void setParent(Node *parent);
    void setRight(Node *right);
    void setWeight(int weight);
    void setUseValue(bool val);
private:
	uint8_t c;
	int weight;
    bool use_value;
	Node* left;
	Node* right;
	Node* parent;
};

}//namespace htf;
#endif /* HUFFMAN_H */

